/**
 * @file rtk_service.c
 * @author LokLiang (lokliang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-01
 *
 * @copyright Copyright (c) 2023
 *
 */

#include "prv_rtk_class.h"

#undef CONFIG_SYS_LOG_CONS_ON
#define CONFIG_SYS_LOG_CONS_ON 1

static u8_t s_tick_enable;

static void _rtk_service_stack_sp(struct rtk_thread_handle *thread);
static void _rtk_service_cpu_log(void);
static void _rtk_service_ass_format(char *str, size_t size, size_t ass_type);
static void _rtk_service_scan_err_stack(bool stop);
static void _rtk_service_thread_stack_check(void *arg);
static void _rtk_service_delete_thread(void); // 从待删除链中取出所有待删除的线程并执行删除

void rtk_isr_hardfault_check(void)
{
    CONS_PRINT("\r\nError: Hard fault!\r\n\r\n");

    /* 扫描一次所有线程栈剩余量 */
    rtk_thread_list_reset();
    for (;;)
    {
        rtk_thread_t *test_thread = rtk_thread_list_next();
        if (test_thread == NULL)
        {
            break;
        }
        _rtk_service_stack_remain(test_thread->hdl);
    }

    /* 检测栈用穿的线程 */
    _rtk_service_scan_err_stack(false);
    rtk_service_print_trace((rtk_thread_t *)&curr_thread_handle);
    rtk_service_print_sysinfo();
    volatile int i = 0;
    while (i == 0)
    {
    }
}

/**
 * @brief 滴答时钟中断服务
 */
void _rtk_isr_tick(void)
{
    if (s_tick_enable)
    {
        int flag = 0;
        struct rtk_thread_handle *thread_from = curr_thread_handle;

        _rtk_service_cpu_log();

        if ((int)(++(cm_rtk->systime_tick) - cm_rtk->systime_early) >= 0)
        {
            flag = 1;
        }

        if (thread_from->slice_count)
        {
            if (--thread_from->slice_count == 0) // 到达轮换时间
            {
                flag = 1;
            }
        }

        if (flag && cm_rtk->thread_from == NULL)
        {
            _rtk_service_switch_to_tick(); // ==> _rtk_service_thread_idle()
        }
    }
}

void _rtk_service_switch_to_tick(void)
{
    size_t nest_int = rtk_cpu_interrupt_save();

    if (cm_rtk->thread_from == NULL)
    {
        cm_rtk->thread_from = curr_thread_handle;

        struct rtk_thread_handle *thread_from = cm_rtk->thread_from;
        struct rtk_thread_handle *thread_to = cm_rtk->thread_idle.hdl;

        cm_rtk->nest_sched++;

        curr_thread_handle = thread_to;
        rtk_cpu_switch_to(thread_from, thread_to); // ==> _rtk_service_thread_idle()
    }

    rtk_cpu_interrupt_restore(nest_int);
}

void _rtk_service_thread_idle(void *arg)
{
    rtk_tick_init(CONFIG_RTK_TICKS_HZ);
    s_tick_enable = 1;
    cm_rtk->nest_sched = 0;
    _rtk_list_atomic_suspend(curr_thread_handle);

    for (;;)
    {
        struct rtk_thread_handle *thread_from = cm_rtk->thread_from; // 原被打断的原线程

        if (thread_from)
        {
            /* 检测被阻断的线程的栈 */
            _rtk_service_stack_sp(thread_from);

            /* 从待删除链中取出所有待删除的线程并执行删除 */
            if (slist_peek_head(&cm_rtk->slist_delete))
            {
                _rtk_service_delete_thread();
            }

            /* 把定时时间到达的线程连接到就绪链 */
            if ((int)(cm_rtk->systime_tick - cm_rtk->systime_early) >= 0)
            {
                _rtk_list_atomic_pend_timeup();
            }

            /* 时间片轮换 */
            if (thread_from->control.slice_ticks != 0 && thread_from->slice_count == 0) // 到达轮换时间
            {
                struct rtk_thread_handle *next_thread = _rtk_list_peek_next(&thread_from->state_node);
                if (next_thread && thread_from != next_thread) // 不止一个线程
                {
                    _RTK_ASS_FALSE(thread_from->curr_prior != next_thread->curr_prior, "");
                    _rtk_list_atomic_yield(thread_from);
                }
                else
                {
                    thread_from->slice_count = thread_from->control.slice_ticks;
                }
            }

            size_t nest_int = rtk_cpu_interrupt_save();

            _RTK_ASS_FALSE(cm_rtk->nest_sched == 0, "");

            if (--cm_rtk->nest_sched == 0)
            {
                thread_from = next_thread_handle;
            }

            cm_rtk->thread_from = NULL;

            _rtk_scheduler_do_swap(cm_rtk->thread_idle.hdl, thread_from);

            rtk_cpu_interrupt_restore(nest_int);
        }
        else
        {
            if (cm_rtk->thread_idle.hdl == next_thread_handle)
            {
                if (cm_rtk->cpu_log.pending == 1)
                {
                    if (cm_rtk->cpu_log.max_incr < cm_rtk->cpu_log.idle_incr)
                        cm_rtk->cpu_log.max_incr = cm_rtk->cpu_log.idle_incr;
                    cm_rtk->cpu_log.idle_incr = 0;
                    cm_rtk->cpu_log.pending = 0;
                }

                if (s_tick_enable)
                {
                    cm_rtk->cpu_log.idle_incr++;
                }
            }
            else
            {
                size_t nest_int = rtk_cpu_interrupt_save();

                cm_rtk->thread_from = curr_thread_handle;

                cm_rtk->nest_sched++;

                rtk_cpu_interrupt_restore(nest_int);
            }
        }
    }
}

void _rtk_service_thread_free(struct rtk_thread_handle *thread)
{
    rtk_cpu_delete_thread(thread);

    /* 释放线程栈内存 */
    if (thread->flag & _RTK_THREAD_FLAG_HEAP)
    {
#if defined(CONFIG_RTK_STACK_CHECK)
        if (cm_rtk->stack_grow_up)
        {
            rtk_heap_free(&((uint8_t *)thread->stack_base)[0]);
        }
        else
        {
            rtk_heap_free(&((uint8_t *)thread->stack_base)[-sizeof(cm_rtk->MemDetector_Head)]);
        }
#else
        rtk_heap_free(thread->stack_base);
#endif
    }

    /* 释放线程控制块内存 */
    rtk_heapk_free(thread);
}

void rtk_service_tick_pause(void)
{
    _RTK_TRACE_ENTRY();
    s_tick_enable = 0;
    _RTK_TRACE_EXIT();
}

void rtk_service_tick_start(void)
{
    _RTK_TRACE_ENTRY();
    s_tick_enable = 1;
    _RTK_TRACE_EXIT();
}

rtk_err_t rtk_service_mem_check_start(rtk_tick_t pre_ticks, rtk_prior_t priority)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();

    size_t sched_nest = rtk_sched_suspend();
    rtk_err_t ret;

    /* 创建线程 */
    if (cm_rtk->thread_mem_check.hdl == NULL)
    {
        size_t arg = pre_ticks;

        rtk_thread_t *thread_handle = rtk_thread_create(&cm_rtk->thread_mem_check,
                                                        "sys-memchk",                    // 线程名
                                                        _rtk_service_thread_stack_check, // 线程入口地址
                                                        (void *)arg,                     // 线程入口参数
                                                        sizeof(size_t) * 0x70,           // 栈大小（字节）
                                                        priority,                        // 优先级
                                                        0                                // 被轮换的时间（值为 0 时不被轮换）
        );

        if (thread_handle)
        {
            struct rtk_thread_handle *thread = cm_rtk->thread_mem_check.hdl;
            thread->flag |= _RTK_THREAD_FLAG_SYS;
            ret = RTK_OK;
        }
        else
        {
            ret = RTK_NOMEM;
        }
    }
    else
    {
        _RTK_WRN("thread already started");
        ret = RTK_FAIL;
    }

    rtk_sched_resume(sched_nest);

    _RTK_TRACE_EXIT();
    return ret;
}

rtk_err_t rtk_service_mem_check_stop(void)
{
    _RTK_TRACE_ENTRY();

    rtk_err_t ret;

    if (cm_rtk->thread_mem_check.hdl == NULL)
    {
        _RTK_WRN("thread already stoped");
        ret = RTK_FAIL;
    }
    else
    {
        ret = rtk_thread_delete(&cm_rtk->thread_mem_check);
    }

    _RTK_TRACE_EXIT();
    return ret;
}

rtk_thread_t *rtk_service_get_idle_thread(void)
{
    return &cm_rtk->thread_idle;
}

u8_t rtk_get_cpu_usage(void)
{
    _RTK_TRACE_ENTRY();

    u8_t ret;

    if (cm_rtk->cpu_log.max_incr < cm_rtk->cpu_log.idle_incr)
    {
        cm_rtk->cpu_log.max_incr = cm_rtk->cpu_log.idle_incr;
    }

    if (cm_rtk->cpu_log.max_incr)
    {
        ret = (100 - ((u32_t)cm_rtk->cpu_log.curr_incr * 100 + (u32_t)cm_rtk->cpu_log.max_incr / 2) / cm_rtk->cpu_log.max_incr);
    }
    else
    {
        ret = 100;
    }

    _RTK_TRACE_EXIT();
    return ret;
}

rtk_hdl_t rtk_find_handle(const char *name)
{
    _RTK_TRACE_ENTRY();
    rtk_hdl_t ret = rtk_heapk_block_base((char *)name, strlen(name) + 1);
    _RTK_TRACE_EXIT();
    return ret;
}

unsigned rtk_get_sys_ticks(void)
{
    return cm_rtk->systime_tick;
}

unsigned rtk_get_remain_ticks(void)
{
    return cm_rtk->systime_early - cm_rtk->systime_tick;
}

unsigned rtk_ticks_to_msec(unsigned ticks)
{
    unsigned ret;

    if (ticks == 0)
    {
        return 0;
    }

    if ((CONFIG_RTK_TICKS_HZ) < 1000U)
    {
        ret = (ticks * (1000U / (CONFIG_RTK_TICKS_HZ)));
        if (ret < ticks)
        {
            ret = RTK_WAIT_FOREVER;
        }
    }
    else
    {
        ret = (ticks / ((CONFIG_RTK_TICKS_HZ) / 1000U));
    }

    if (ret == 0)
    {
        ret = 1;
    }

    return ret;
}

unsigned rtk_msec_to_ticks(unsigned ms)
{
    unsigned ret;

    if (ms == 0)
    {
        return 0;
    }

    if ((CONFIG_RTK_TICKS_HZ) < 1000U)
    {
        ret = (ms / (1000U / (CONFIG_RTK_TICKS_HZ)));
    }
    else
    {
        ret = (ms * ((CONFIG_RTK_TICKS_HZ) / 1000U));
        if (ret < ms)
        {
            ret = RTK_WAIT_FOREVER;
        }
    }

    if (ret == 0)
    {
        ret = 1;
    }

    return ret;
}

static void _rtk_service_thread_stack_check(void *arg)
{
    for (;;)
    {
        rtk_thread_sleep((rtk_tick_t)arg);

        _rtk_service_scan_err_stack(true);

        /* 扫描一次所有线程栈剩余量 */
        rtk_thread_list_reset();
        for (;;)
        {
            size_t sched_nest = rtk_sched_suspend();
            rtk_thread_t *test_thread = rtk_thread_list_next();
            if (test_thread == NULL)
            {
                rtk_sched_resume(sched_nest);
                break;
            }
            else
            {
                if (rtk_thread_is_valid(test_thread) == false)
                {
                    _rtk_service_scan_err_stack(true);
                }
                _rtk_service_stack_remain(test_thread->hdl);
                rtk_sched_resume(sched_nest);
            }
        }
    }
}

static void _rtk_service_delete_thread(void)
{
    for (;;)
    {
        size_t nest_int = rtk_cpu_interrupt_save();
        slist_node_t *node = slist_take_head(&cm_rtk->slist_delete);
        rtk_cpu_interrupt_restore(nest_int);

        if (node)
        {
            struct rtk_thread_handle *thread = _RTK_CONTAINER_OF(node, struct rtk_thread_handle, active_node);

            _rtk_service_thread_free(thread);
        }
        else
        {
            return;
        }
    }
}

/**
 * @brief 扫描所有线程，并根据保存上下文的指针和栈内存余量扫描的值，查找可能栈溢出的线程
 *
 * @param stop 如果是找到错误的线程则暂停运行
 */
static void _rtk_service_scan_err_stack(bool stop)
{
    struct rtk_thread_handle *err_thread = NULL;
    void *stack_base_cmp = NULL;
    volatile bool flag = stop;

    /* 检查是否有用穿栈顶的线程 */
    rtk_thread_list_reset();
    for (;;)
    {
        size_t sched_nest = rtk_sched_suspend();
        rtk_thread_t *test_thread = rtk_thread_list_next();
        if (test_thread == NULL)
        {
            rtk_sched_resume(sched_nest);
            break;
        }
        else
        {
            struct rtk_thread_handle *thread = test_thread->hdl;

            size_t sp = (size_t)thread->pSP;
            if (cm_rtk->stack_grow_up) // 栈向上生长
            {
                if (sp > (size_t)thread->stack_base + thread->stack_size)
                {
                    err_thread = thread;
                    rtk_sched_resume(sched_nest);
                    break;
                }
            }
            else // 栈向下生长
            {
                if (sp < (size_t)thread->stack_base)
                {
                    err_thread = thread;
                    rtk_sched_resume(sched_nest);
                    break;
                }
            }

#if defined(CONFIG_RTK_STACK_CHECK)

            if (thread->stack_remain <= 0)
            {
                if (stack_base_cmp == NULL)
                {
                    stack_base_cmp = thread->stack_base;
                    err_thread = thread;
                }
                else
                {
                    if (cm_rtk->stack_grow_up) // 栈向上生长
                    {
                        if (thread->stack_base < stack_base_cmp)
                        {
                            err_thread = thread;
                        }
                    }
                    else // 栈向下生长
                    {
                        if (thread->stack_base > stack_base_cmp)
                        {
                            err_thread = thread;
                        }
                    }
                }
            }

#endif /* #if defined(CONFIG_RTK_STACK_CHECK) */
            rtk_sched_resume(sched_nest);
        }
    }

    if (cm_rtk->MemDetector_Head != _RTK_HEAP_DET_VALUE || cm_rtk->MemDetector_Tail != cm_rtk->MemDetector_Head) // 内存监测值损坏，很可能是栈被用穿而受到破坏
    {
        CONS_PRINT("class memory error\r\n");
        while (flag)
        {
        }
    }
    else if (cm_rtk->heap_log)
    {
        CONS_PRINT("operating heap memory error: %p\r\n", cm_rtk->heap_log);
        while (flag)
        {
        }
    }
    else if (err_thread != NULL)
    {
        CONS_PRINT("stack over flow: %s\r\n", err_thread->name);
        while (flag)
        {
        }
    }
}

bool _rtk_service_handle_is_valid(void *handle)
{
    size_t sched_nest = rtk_sched_suspend();

    if (handle != NULL && rtk_heapk_is_valid(*(void **)handle))
    {
        rtk_sched_resume(sched_nest);
        return true;
    }
    else
    {
        rtk_sched_resume(sched_nest);
        return false;
    }
}

void _rtk_service_trace_entry(void *s, const char *func)
{
    if (curr_thread_handle)
    {
        struct
        {
            slist_node_t node;
            const char *func;
        } *trace = s;
        slist_init_node(&trace->node);
        trace->func = func;
        size_t nest = rtk_cpu_interrupt_save();
        slist_insert_front(&curr_thread_handle->slist_trace, &trace->node);
        rtk_cpu_interrupt_restore(nest);
    }
}

void _rtk_service_trace_exit(void *s)
{
    if (curr_thread_handle)
    {
        struct
        {
            slist_node_t node;
            const char *func;
        } *trace = s;
        size_t nest = rtk_cpu_interrupt_save();
        slist_remove(&curr_thread_handle->slist_trace, &trace->node);
        rtk_cpu_interrupt_restore(nest);
    }
}

void _rtk_service_isr_check_log(const char *func)
{
    _SYS_LOG(1, _COLOR_R "[ERR]" _COLOR_END " - ",
             "%s(): This function cannot be used in interrupts\r\n",
             func);
    CONS_ABORT();
}

void _rtk_service_isr_check_sched(const char *func)
{
    _SYS_LOG(1, _COLOR_Y "[WRN]" _COLOR_END " -  ",
             "%s(): Function fail when scheduler or interrupt was disabled",
             func);
}

rtk_err_t _rtk_service_assert_check_handle(size_t ass_type, void *handle, const char *file, u32_t line, const char *func)
{
    size_t sched_nest = rtk_sched_suspend();

    char ass[0x20];
    char msg[0x40];
    if (handle != NULL && rtk_heapk_is_valid(*(void **)handle))
    {
        rtk_sched_resume(sched_nest);
        return RTK_OK;
    }
    else
    {
        SYS_SNPRINT(msg, sizeof(msg), "Handle corruption: %p", *(void **)handle);
    }

    _rtk_service_ass_format(ass, sizeof(ass), ass_type);
    CONS_PRINT("%s%s:%d, %s(): %s\r\n", ass, _FILENAME(file), line, func, msg);
    rtk_sched_resume(sched_nest);
    return RTK_E_HDL;
}

rtk_err_t _rtk_service_assert_check_thread(size_t ass_type, rtk_thread_t *thread_handle, const char *file, u32_t line, const char *func)
{
    rtk_err_t ret;
    char ass[0x20];
    char msg[0x40];

    size_t sched_nest = rtk_sched_suspend();

    if (rtk_thread_is_valid(thread_handle) == false)
    {
        if (thread_handle == NULL)
        {
            ret = RTK_E_PARAM;
            SYS_SNPRINT(msg, sizeof(msg), "Parameter error: handle = NULL");
        }
        else
        {
            ret = RTK_E_HDL;
            struct rtk_thread_handle *thread = thread_handle->hdl;
            SYS_SNPRINT(msg, sizeof(msg), "Handle corruption: %p, name = '%s'", thread, thread->name);
        }
    }
    else
    {
#if defined(CONFIG_RTK_STACK_CHECK)
        struct rtk_thread_handle *thread = thread_handle->hdl;

        if (cm_rtk->stack_grow_up)
        {
            if (((size_t *)&((uint8_t *)thread->stack_base)[thread->stack_size])[0] == _RTK_HEAP_DET_VALUE)
            {
                rtk_sched_resume(sched_nest);
                return RTK_OK;
            }
        }
        else
        {
            if (((size_t *)thread->stack_base)[-1] == _RTK_HEAP_DET_VALUE)
            {
                rtk_sched_resume(sched_nest);
                return RTK_OK;
            }
        }
        ret = RTK_E_STACK;
#else
        ret = RTK_OK;
#endif
    }

    _rtk_service_ass_format(ass, sizeof(ass), ass_type);
    CONS_PRINT("%s%s:%d, %s(): %s\r\n", ass, _FILENAME(file), line, func, msg);
    rtk_sched_resume(sched_nest);
    return ret;
}

void *_rtk_name_malloc(const char *name, size_t size)
{
    if (name == NULL || *name == '\0')
    {
        name = "N";
    }
    if (rtk_heapk_block_base(name, strlen(name) + 1))
    {
        size_t sched_nest = rtk_sched_suspend();

        size_t num = 1;
        size_t len = SYS_SNPRINT(cm_rtk->name_buf, sizeof(cm_rtk->name_buf), "%s", name);
        size_t base_len = (len > sizeof(cm_rtk->name_buf) - 5 ? len > sizeof(cm_rtk->name_buf) - 5 : len);
        do
        {
            cm_rtk->name_buf[base_len] = '\0';
            len = SYS_SNPRINT(&cm_rtk->name_buf[base_len], sizeof(cm_rtk->name_buf) - base_len, "(%d)", ++num) + base_len;
        } while (rtk_heapk_block_base(cm_rtk->name_buf, len + 1) && num < 1000);

        void *ret = rtk_heapk_malloc(size, cm_rtk->name_buf, len + 1, 0);

        rtk_sched_resume(sched_nest);

        return ret;
    }
    else
    {
        return rtk_heapk_malloc(size, name, strlen(name) + 1, 0);
    }
}

/**
 * @brief CPU 使用记录
 *
 */
static void _rtk_service_cpu_log(void)
{
    if (cm_rtk->systime_tick & 1)
    {
        size_t tmp = cm_rtk->cpu_log.max_incr / 512;

        if (cm_rtk->cpu_log.pending == 0) // 在上一节拍中，空闲线程曾运行过
        {
            if (cm_rtk->cpu_log.idle_incr > cm_rtk->cpu_log.curr_incr)
            {
                cm_rtk->cpu_log.curr_incr += tmp;
            }
            else if (cm_rtk->cpu_log.idle_incr < cm_rtk->cpu_log.curr_incr)
            {
                if (cm_rtk->cpu_log.curr_incr > tmp)
                {
                    cm_rtk->cpu_log.curr_incr -= tmp;
                }
                else
                {
                    cm_rtk->cpu_log.curr_incr = 0;
                }
            }

            cm_rtk->cpu_log.pending = 1;
        }
        else
        {
            if (cm_rtk->cpu_log.curr_incr > tmp)
            {
                cm_rtk->cpu_log.curr_incr -= tmp;
            }
            else
            {
                cm_rtk->cpu_log.curr_incr = 0;
            }
        }
    }
}

static void _rtk_service_ass_format(char *str, size_t size, size_t ass_type)
{
    switch (ass_type)
    {
    case 1:
    {
        SYS_SNPRINT(str, size, "%s[ERR]%s * ", _COLOR_R, _COLOR_END); // 红 RED
        break;
    }
    case 2:
    {
        SYS_SNPRINT(str, size, "%s[WRN]%s * ", _COLOR_G, _COLOR_END); // 绿 GREEN
        break;
    }
    case 3:
    {
        SYS_SNPRINT(str, size, "%s[WRN]%s * ", _COLOR_Y, _COLOR_END); // 黄 YELLOW
        break;
    }
    case 4:
    {
        SYS_SNPRINT(str, size, "%s[WRN]%s * ", _COLOR_B, _COLOR_END); // 蓝 BLUE
        break;
    }
    case 5:
    {
        SYS_SNPRINT(str, size, "%s[WRN]%s * ", _COLOR_P, _COLOR_END); // 紫 PURPLE
        break;
    }
    case 6:
    {
        SYS_SNPRINT(str, size, "%s[WRN]%s * ", _COLOR_C, _COLOR_END); // 青 CYAN
        break;
    }
    case 7:
    {
        SYS_SNPRINT(str, size, "%s[ASS]%s # ", _COLOR_RY, _COLOR_END); // 红底黄字
        break;
    }
    default:
    {
        str[0] = '\0';
        break;
    }
    }
}

static void _rtk_service_stack_sp(struct rtk_thread_handle *thread)
{
#if defined(CONFIG_RTK_STACK_CHECK)

    int stack_remain = thread->stack_remain;
    int Newstack_remain;

    if (thread->curr_state != THREAD_STATE_CLOSED)
    {
        /* 记录栈使用 */
        if (cm_rtk->stack_grow_up == false) // 栈向下生长
        {
            Newstack_remain = (int)thread->pSP - (int)thread->stack_base;
        }
        else
        {
            size_t Data = (size_t) & ((uint8_t *)thread->stack_base)[thread->stack_size]; // 高址监测值
            Newstack_remain = Data - (int)thread->pSP;
        }

        if (stack_remain > Newstack_remain)
        {
            thread->stack_remain = Newstack_remain;
        }

        if (thread->stack_remain <= 0) // 栈用穿
        {
            _rtk_service_scan_err_stack(true);
        }
    }

#endif /* #if defined(CONFIG_RTK_STACK_CHECK) */
}

int _rtk_service_stack_remain(struct rtk_thread_handle *thread)
{
    int stack_remain = thread->stack_remain;
    size_t SP = (size_t)thread->pSP;
    size_t i;

    if (thread->stack_remain >= 0)
    {
        /* 计算空闲栈的字节数 */
        if (cm_rtk->stack_grow_up) // 栈向上生长
        {
            size_t stack_end = (size_t)thread->stack_base + thread->stack_size;
            if (SP > stack_end)
            {
                stack_remain = -1;
            }

            if (stack_remain > (int)(stack_end - SP))
            {
                stack_remain = stack_end - SP;
            }

            if (stack_remain >= 0)
            {
                for (i = stack_remain / sizeof(int); i-- > 0;)
                {
                    if (((int *)thread->stack_base)[i] != 0)
                    {
                        stack_remain = (stack_remain / sizeof(int) - 1 - i) * sizeof(int);
                        break;
                    }
                }
            }
        }
        else // 栈向下生长
        {
            if (SP < (size_t)thread->stack_base)
            {
                stack_remain = -1;
            }

            if (stack_remain > (int)SP - (int)thread->stack_base)
            {
                stack_remain = (int)SP - (int)thread->stack_base;
            }

            if (stack_remain >= 0)
            {
                for (i = 0; i < stack_remain / sizeof(int); i++)
                {
                    if (((int *)thread->stack_base)[i] != 0)
                    {
                        stack_remain = i * sizeof(int);
                        break;
                    }
                }
            }
        }

        thread->stack_remain = stack_remain;
    }
    else
    {
        stack_remain = -1;
    }

    return stack_remain;
}

/**
 * @brief 打印系统状态和所有线程的状态
 */
void rtk_service_print_sysinfo(void)
{
#define _MSIZE_KB(N) (N) / 0x400, (N) % 0x400 * 10 / 0x400
#define _MSIZE_MB(N) (N) / 0x100000, (N) % 0x100000 * 10 / 0x100000

    _RTK_TRACE_ENTRY();

    size_t num = 0;

    size_t sched_nest = rtk_sched_suspend();

    size_t sys_time = rtk_get_sys_ticks();

    size_t heap_used = rtk_heap_used_size();
    size_t heap_free = rtk_heap_free_size();

    CONS_PRINT("\r\n                ------====== Kernel information ======------\r\n");
    CONS_PRINT("CPU: %d%%\r\n", rtk_get_cpu_usage());
    CONS_PRINT("Run time: %d %02d:%02d:%02d:%03d (D HH:MM:SS:MS)\r\n",
               sys_time / (1000 * 60 * 60 * 24),
               sys_time % (1000 * 60 * 60 * 24) / (1000 * 60 * 60),
               sys_time % (1000 * 60 * 60) / (1000 * 60),
               sys_time % (1000 * 60) / (1000),
               sys_time % (1000) / (1));
    CONS_PRINT("\r\nHeap:\r\n");
    if (heap_used < 0x400)
        CONS_PRINT("  Used: %u B\r\n", heap_used);
    else if (heap_used < 0x100000)
        CONS_PRINT("  Used: %u.%u KiB\r\n", _MSIZE_KB(heap_used));
    else
        CONS_PRINT("  Used: %u.%u MiB\r\n", _MSIZE_MB(heap_used));
    if (heap_free < 0x400)
        CONS_PRINT("  Free: %u B\r\n", heap_free);
    else if (heap_free < 0x100000)
        CONS_PRINT("  Free: %u.%u KiB\r\n", _MSIZE_KB(heap_free));
    else
        CONS_PRINT("  Free: %u.%u MiB\r\n", _MSIZE_MB(heap_free));

    CONS_PRINT("\r\n--------------------------------------------------------------------------------------\r\n");
    CONS_PRINT(" ID    Handler    State  Prior Tick   StackBase  StackSize    Used  Remain  Name\r\n");
    CONS_PRINT("--------------------------------------------------------------------------------------\r\n\r\n");

    rtk_thread_list_reset();
    for (;;)
    {
        rtk_thread_t *thread_handle = rtk_thread_list_next();
        if (thread_handle == NULL)
        {
            break;
        }
        struct rtk_thread_handle *thread = thread_handle->hdl;
        rtk_thread_state_t state = thread->curr_state;        // 线程状态
        const char *name = thread->name;                      // 获取线程名
        rtk_prior_t priority = thread->curr_prior;            // 获取线程当前的优先级
        u8_t slice_ticks = thread->control.slice_ticks;       // 获取线程当前的轮换时间
        void *stack_base = thread->stack_base;                // 获取线程的栈地址
        size_t stack_size = thread->stack_size;               // 获取线程的栈大小
        int stack_remain = _rtk_service_stack_remain(thread); // 根据线程的使用痕迹，计算剩余最小的栈内存。用穿返回 -1
        char str[20];

        switch (state)
        {
        case THREAD_STATE_CLOSED: // 线程已关闭
        {
            SYS_SNPRINT(str, sizeof(str), "Closing");
            break;
        }
        case THREAD_STATE_DELAYED: // 线程为延时（定时唤醒）状态
        {
            SYS_SNPRINT(str, sizeof(str), "Delayed");
            break;
        }
        case THREAD_STATE_SUSPEND: // 线程为挂起状态
        {
            SYS_SNPRINT(str, sizeof(str), "Suspend");
            break;
        }
        case THREAD_STATE_PENDING: // 线程为就绪状态
        {
            SYS_SNPRINT(str, sizeof(str), "Pending");
            break;
        }
        case THREAD_STATE_RUNNING: // 线程为运行状态
        {
            SYS_SNPRINT(str, sizeof(str), "Running");
            break;
        }
        case THREAD_STATE_WAIT_SEM:   // 线程为等待信号
        case THREAD_STATE_WAIT_MUTEX: // 线程为等待互斥量
        {
            SYS_SNPRINT(str, sizeof(str), "Waiting");
            break;
        }
        }

        CONS_PRINT("%3d 0x%08x  %s  %5d %4d  0x%08x  %9d %7d %7d  %s\r\n\r\n",
                   ++num,
                   (int)thread_handle->hdl,
                   str,
                   priority,
                   slice_ticks,
                   (int)stack_base,
                   stack_size,
                   stack_size - stack_remain,
                   stack_remain,
                   name);
    }
    CONS_PRINT("--------------------------------------------------------------------------------------\r\n\r\n");

    rtk_sched_resume(sched_nest);

    _RTK_TRACE_EXIT();

#undef _MSIZE_KB
#undef _MSIZE_MB
}

void rtk_service_print_trace(rtk_thread_t *thread_handle)
{
    struct rtk_thread_handle *thread = thread_handle->hdl;
    slist_t *slist_trace = &thread->slist_trace;

    size_t nest = rtk_cpu_interrupt_save();

    slist_node_t *first_node = slist_peek_head(slist_trace);
    slist_node_t *last_node = slist_peek_tail(slist_trace);

    if (last_node)
    {
        CONS_PRINT("tracing thread '%s'\r\n", thread->name);
        do
        {
            struct rtk_trace
            {
                slist_node_t node;
                const char *func;
            } *trace = _RTK_CONTAINER_OF(last_node, struct rtk_trace, node);

            CONS_PRINT("  >>> %s\r\n", trace->func);

            last_node = slist_peek_prev(slist_trace, last_node);

        } while (last_node && last_node != first_node);
    }

    rtk_cpu_interrupt_restore(nest);
}
